import xml.etree.ElementTree as ET
from datetime import datetime, timedelta
import os
import json
from core.content_format import format_content
class RSS:
    cache_dir = os.path.normpath("data/cache/rss")
    content_cache_dir = os.path.normpath("data/cache/content")
    rss_file="all"
    
    def __init__(self, name:str="all",cache_dir: str = None,ext:str="rss"):
        if cache_dir is not None:
            self.cache_dir = cache_dir
        self.ext=ext    
        os.makedirs(self.cache_dir, exist_ok=True)
        os.makedirs(self.content_cache_dir, exist_ok=True)
        normalized_path = os.path.normpath(f"{self.cache_dir}/{name}.{ext}")
        if not normalized_path.startswith(self.cache_dir):
            raise ValueError("Invalid file path: Path traversal detected.")
        self.rss_file = normalized_path
        pass
    def get_type(self):
        if self.ext in ["rss","atom","md","txt"]:
            return "application/xml"
        if self.ext=="json":
            return "application/json"
        return "text/plain"
    
    def cache_content(self, content_id: str, content: dict):
        """缓存文章内容"""
        content["content"]=self.add_logo_prefix_to_urls(content["content"])
        content_path = os.path.normpath(f"{self.content_cache_dir}/{content_id}.json")
        if not content_path.startswith(self.content_cache_dir):
            raise ValueError("Invalid content path: Path traversal detected.")
        
        with open(content_path, "w", encoding="utf-8") as f:
            json.dump(content, f, ensure_ascii=False, indent=2)

    def get_cached_content(self, content_id: str) -> dict:
        """获取缓存的文章内容"""
        content_path = os.path.normpath(f"{self.content_cache_dir}/{content_id}.json")
        if not content_path.startswith(self.content_cache_dir):
            raise ValueError("Invalid content path: Path traversal detected.")
        
        try:
            with open(content_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except FileNotFoundError:
            return None
    def serialize_datetime(self,obj):
        if isinstance(obj, datetime):
            return obj.isoformat
        return obj
        
    def datetime_to_rfc822(self,dt:str)->str:
        """将datetime对象或时间字符串转换为RFC 822格式的时间字符串"""
        dt = datetime.fromisoformat(dt)
        return dt.strftime('%a, %d %b %Y %H:%M:%S %z')
    
    def add_logo_prefix_to_urls(self, text: str) -> str:
        """在字符串中所有http/https开头的图片URL前添加/static/res/logo/前缀
        
        Args:
            text: 包含URL的原始字符串
            
        Returns:
            处理后的字符串，所有图片URL前添加了前缀
        """
        import re
        try:
            pattern = re.compile(r'(<img[^>]*src=["\'])(?!\/static\/res\/logo\/)([^"\']*)', re.IGNORECASE)
            return pattern.sub(r'\1/static/res/logo/\2', text)
        except:
            return text
       
    def generate_rss(self,rss_list: dict, title: str = "Mp-We-Rss", 
                    link: str = "https://github.com/rachelos/we-mp-rss",
                    description: str = "RSS频道", language: str = "zh-CN",image_url:str=""):
        from core.config import cfg
        full_context=bool(cfg.get("rss.full_context",False))
        
        # 创建根元素(RSS标准)
        rss = ET.Element("rss", version="2.0")
        if full_context==True:
            rss.attrib["xmlns:content"] = "http://purl.org/rss/1.0/modules/content/"
        channel=ET.SubElement(rss, "channel")
        # 设置渠道信息
        ET.SubElement(channel, "title").text = title
        ET.SubElement(channel, "link").text = link
        ET.SubElement(channel, "description").text = description
        ET.SubElement(channel, "language").text = language
        ET.SubElement(channel, "generator").text = "Mp-We-Rss"
        ET.SubElement(channel, "lastBuildDate").text =datetime.now().strftime("%a, %d %b %Y %H:%M:%S %z")
    
        # 设置image子项
        if cfg.get("rss.add_cover",False)==True and image_url != "":
            image = ET.SubElement(channel, "image")
            ET.SubElement(image, "url").text = image_url
            ET.SubElement(image, "title").text = title
            ET.SubElement(image, "link").text = link

        for rss_item in rss_list:
            item = ET.SubElement(channel, "item")
            ET.SubElement(item, "id").text = rss_item["id"]
            ET.SubElement(item, "title").text = rss_item["title"]
            ET.SubElement(item, "description").text = rss_item["description"] 
            ET.SubElement(item, "guid").text = rss_item["link"]
            # 添加图片封面
            if cfg.get("rss.add_cover",False)==True:
                enclosure = ET.SubElement(item, "enclosure")
                enclosure.set("url", rss_item["image"])
                enclosure.set("length", "0")
                enclosure.set("type", "image/jpeg")
            if full_context==True:
                try:
                    if cfg.get("rss.cdata",False)==True:
                        content = f"<![CDATA[{str(rss_item['content'])}]]>"  # 使用CDATA包裹内容
                    else:
                        content = str(rss_item['content'])
                    ET.SubElement(item, "content:encoded").text = content
                except Exception as e:
                    print(f"Error adding content:encoded element: {e}")
                pass
            # ET.SubElement(item, "category").text = rss_item["category"]
            # ET.SubElement(item, "author").text = rss_item["author"]
            ET.SubElement(item, "link").text = rss_item["link"]
            ET.SubElement(item, "pubDate").text = self.datetime_to_rfc822(str(rss_item["updated"]))

        # 生成XML字符串(添加声明和美化输出)
        tree_str = '<?xml version="1.0" encoding="utf-8"?>\r\n' + \
                ET.tostring(rss, encoding="utf-8", method="xml", short_empty_elements=False).decode("utf-8")
        
        if self.rss_file is not None:
            with open(self.rss_file, "w", encoding="utf-8") as f:
                f.write(tree_str)
        return tree_str
     
    def generate_atom(self,rss_list: dict, title: str = "Mp-We-Rss", 
                    link: str = "https://github.com/rachelos/we-mp-rss",
                    description: str = "RSS频道", language: str = "zh-CN",image_url:str="") -> str:
        """生成Atom格式的RSS内容
        
        Args:
            rss_list: RSS条目列表
            title: 频道标题
            link: 频道链接
            description: 频道描述
            language: 语言
            
        Returns:
            Atom格式的XML字符串
        """
        from core.config import cfg
        full_context = bool(cfg.get("rss.full_context", False))
        
        # 创建根元素(Atom标准)
        feed = ET.Element("feed", xmlns="http://www.w3.org/2005/Atom")
        if full_context==True:
            feed.attrib["xmlns:content"] = "http://purl.org/rss/1.0/modules/content/"
        ET.SubElement(feed, "title").text = title
        ET.SubElement(feed, "link",rel="alternate", href=link)
        ET.SubElement(feed, "link",rel="icon", href=image_url)
        ET.SubElement(feed, "logo").text=str(image_url)
        ET.SubElement(feed, "icon").text=str(image_url)
        ET.SubElement(feed, "updated").text = datetime.now().strftime("%a, %d %b %Y %H:%M:%S %z")
        ET.SubElement(feed, "id").text = str(link)
        ET.SubElement(feed, "author").text = "Mp-We-Rss"
        # 设置image子项
        if cfg.get("rss.add_cover",False)==True and image_url != "":
            image = ET.SubElement(feed, "image")
            ET.SubElement(image, "url").text = str(image_url)
            ET.SubElement(image, "title").text = str(title)
            ET.SubElement(image, "link").text = str(link)
        for rss_item in rss_list:
            entry = ET.SubElement(feed, "entry")
            ET.SubElement(entry, "id").text = rss_item["id"]
            ET.SubElement(entry, "title").text = str(rss_item["title"])
            ET.SubElement(entry, "link", href=str(rss_item["link"]))
            ET.SubElement(entry, "updated").text =self.datetime_to_rfc822(str(rss_item["updated"]))
            ET.SubElement(entry, "summary").text = str(rss_item["description"])
            ET.SubElement(entry, "author").text = str(rss_item["mp_name"])
             # 添加图片封面
            if cfg.get("rss.add_cover",False)==True:
                enclosure = ET.SubElement(entry, "enclosure")
                enclosure.set("url", str(rss_item["image"]))
                enclosure.set("length", "0")
                enclosure.set("type", "image/jpeg")
            
            if full_context:
                type=self.get_content_type()
                # content = ET.SubElement(entry, "content", type=f"{str(type)}") 
                # content.text = format_content(rss_item["content"],type)
                content=format_content(rss_item["content"],type)
                try:
                    if cfg.get("rss.cdata",False)==True:
                        content = f"<![CDATA[{content}]]>"  # 使用CDATA包裹内容
                    else:
                        ET.SubElement(entry, "content:encoded").text = content
                except Exception as e:
                    print(f"Error adding content:encoded element: {e}")
                pass
        # 生成XML字符串
        tree_str = '<?xml version="1.0" encoding="utf-8"?>\r\n' + \
                  ET.tostring(feed, encoding="utf-8", method="xml").decode("utf-8")
        
        if self.rss_file is not None:
            with open(self.rss_file, "w", encoding="utf-8") as f:
                f.write(tree_str)
        return tree_str
    def set_content_type(self,type:str=None):
        self.content_type=type
    def get_content_type(self)->str:
        ext=self.ext
        if ext in("atom","xml","json","markdown"):
            return "html",
        elif ext in("md","jmd"):
            return "markdown"
        elif ext in("txt"):
            return "text"
        return "html"
    def generate_json(self, rss_list: dict,title: str = "Mp-We-Rss", 
                    link: str = "https://github.com/rachelos/we-mp-rss",
                    description: str = "RSS频道", language: str = "zh-CN",image_url:str="") -> str:
        """获取JSON格式的RSS内容
        
        Args:
            rss_list: RSS条目列表
            
        Returns:
            JSON格式的字符串
        """
        type=self.get_content_type()
        result = {
            "name":title,
            "link":link,
            "description":description,
            "language": language,
            "cover":image_url,
            "items": [
                {
                    "id": item["id"],
                    "title": item["title"],
                    "description": item["description"],
                    "link": item["link"],
                    "updated": item["updated"].isoformat() if isinstance(item["updated"], datetime) else item["updated"],
                    "content": format_content(item["content"],type),
                    "channel_name": item.get("mp_name", ""),
                    "feed": item.get("feed")
                } for item in rss_list
            ]
        }
        return json.dumps(result, ensure_ascii=False, indent=2, default=self.serialize_datetime)

    def get_cache(self):
        if not hasattr(self, 'rss_file') or not self.rss_file:
               return None
        try:
            with open(self.rss_file, "r", encoding="utf-8") as f:
                return f.read()  
        except FileNotFoundError:
            return None     
    def generate(self,rss_list: dict,ext=str, title: str = "Mp-We-Rss", 
                    link: str = "https://github.com/rachelos/we-mp-rss",
                    description: str = "RSS频道", language: str = "zh-CN",image_url:str="",template:str=None) -> str:
        """根据扩展名获取对应格式的RSS内容
        
        Args:
            rss_list: RSS条目列表
            ext: 文件扩展名(.rss/.xml/.atom/.json)
            **kwargs: 传递给各格式生成方法的参数
            
        Returns:
            对应格式的字符串
            
        Raises:
            ValueError: 当扩展名不支持时
        """
        ext = ext.lower().strip('.')
        self.ext=ext
        if ext in ('rss', 'xml'):
            return self.generate_rss(rss_list, title=title, link=link, description=description,language=language,image_url=image_url)
        elif ext in ('atom','md','txt'):
            return self.generate_atom(rss_list, title=title, link=link, description=description,language=language,image_url=image_url)
        elif ext in ('json','jmd'):
            return self.generate_json(rss_list, title=title, link=link, description=description,language=language,image_url=image_url)
        elif template is not None:
            return self.generate_by_template(rss_list,template, title=title, link=link, description=description,language=language,image_url=image_url)
        else:
            raise ValueError(f"Unsupported extension: {ext}")
    def generate_by_template(self,rss_list: dict, template: str, title: str = "Mp-We-Rss",link: str = "https://github.com/rachelos/we-mp-rss",description: str = "RSS频道",language: str = "zh-CN",image_url:str=""):
            from core.lax import TemplateParser
            template = TemplateParser(template)
            return template.render({"articles": rss_list, "title": title,"link":link,"description":description,"language":language,"image_url":image_url})
            pass
    def clear_cache(self,mp_id:str=""):

        """清除所有缓存文件
        
        删除data/cache/rss和data/cache/content目录中包含'mp_id'的文件
        保持与现有方法相同的路径安全检查机制
        """
        import shutil
        
        # 清除rss缓存目录
        if os.path.exists(self.cache_dir):
            for filename in os.listdir(self.cache_dir):
                if f'{mp_id}_' not in filename:
                    continue
                file_path = os.path.normpath(f"{self.cache_dir}/{filename}")
                if not file_path.startswith(self.cache_dir):
                    raise ValueError("Invalid file path: Path traversal detected.")
                try:
                    if os.path.isfile(file_path):
                        os.unlink(file_path)
                except Exception as e:
                    print(f"Error deleting {file_path}: {e}")